package io.simple.sessions;

import com.google.common.io.BaseEncoding;
import io.simple.core.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by rehak on 2/25/14.
 */
public class LocalSessions implements Sessions {

    private static final Logger LOGGER = LoggerFactory.getLogger(LocalSessions.class);
    private final ConcurrentMap<String, Session> sessionMap = new ConcurrentHashMap<>();
    private final ReentrantLock lock = new ReentrantLock();
    private static final SecureRandom r = new SecureRandom(ByteBuffer.wrap(new byte[8]).putLong(System.currentTimeMillis()).array());

    @Override
    public Session get(String id) {
        return sessionMap.get(id);
    }

    @Override
    public Session get(RequestContext ctx) {
        Object s = ctx.getProperty(Sessions.SESSION_PROP_NAME);
        if (s != null) {
            String sid = (String) s;
            return get(sid);
        }
        return null;
    }

    @Override
    public Session create() {
        lock.lock();
        try {
            String id = generateID();
            // generate while collision (highly improbable)
            while (sessionMap.containsKey(id)) {
                id = generateID();
            }
            Session s = new LocalSession(id, System.currentTimeMillis());
            sessionMap.put(id, s);
            return s;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public Session recreate(String id) {
        lock.lock();
        try {
            Session s = new LocalSession(id, System.currentTimeMillis());
            sessionMap.put(id, s);
            return s;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void refresh(Session session) {
        if (session instanceof LocalSession) {
            ((LocalSession) session).refresh(System.currentTimeMillis());
        } else {
            LOGGER.warn("Unsupported - " + session.getClass());
        }
    }

    @Override
    public void remove(Session session) {
        sessionMap.remove(session.getID());
    }

    @Override
    public void remove(String id) {
        sessionMap.remove(id);
    }

    public static String generateID() {
        byte[] idb = new byte[16];
        r.nextBytes(idb);
        String idHex = BaseEncoding.base16().lowerCase().omitPadding().encode(idb);
        return idHex;
    }

}
